/****************************************************************************
**
** Copyright (C) 2010 Tieto Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Tieto Corporation (info.ostrava@tieto.com)
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial Usage
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Tieto.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Tieto gives you certain additional
** rights.  These rights are described in the Tieto Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
** If you have questions regarding the use of this file, please contact
** Tieto at info.ostrava@tieto.com.
** $QT_END_LICENSE$
**
****************************************************************************/

#include <QtGui/QImage>
#include <QtGui/QColor>
#include <QtGui/QPainter>
#include <QtDebug>

#include "areaindexingmodel.h"

AreaIndexingTask::AreaIndexingTask(AreaIndexingModel &model, QObject *parent)
    : BackgroundTask(QString(tr("Area indexing")), parent),
    _areasCount(0),
    _model(model)
{
    _areaColor = QColor(Qt::black).rgb();
    _pallete.append(QColor(Qt::red).rgb());
    _pallete.append(QColor(Qt::darkRed).rgb());
    _pallete.append(QColor(Qt::green).rgb());
    _pallete.append(QColor(Qt::darkGreen).rgb());
    _pallete.append(QColor(Qt::blue).rgb());
    _pallete.append(QColor(Qt::darkBlue).rgb());
    _pallete.append(QColor(Qt::cyan).rgb());
    _pallete.append(QColor(Qt::darkCyan).rgb());
    _pallete.append(QColor(Qt::magenta).rgb());
    _pallete.append(QColor(Qt::darkMagenta).rgb());
    _pallete.append(QColor(Qt::yellow).rgb());
    _pallete.append(QColor(Qt::darkYellow).rgb());
    _pallete.append(QColor(Qt::gray).rgb());
    _pallete.append(QColor(Qt::darkGray).rgb());
    _pallete.append(QColor(Qt::lightGray).rgb());
}

void AreaIndexingTask::doRun()
{    
    ColorImage image;
    image = _model.detectedAreasImage().copy();
    IndexImage indexImage = IndexImage(image.size());
    int width = image.width();
    int height = image.height();;
    progressRangeChanged(0, height);
    QRgb color = _pallete[0];
    for(int row = 0; row < height; row++) {
        for (int col = 0; col < width; col++) {
            if (fillScanline(image, indexImage, row, col, _areaColor, color)) {
                _areasCount++;
                color = _pallete[_areasCount % _pallete.size()];
            }            
            if (_isCanceled) {
                break;
            }
        }        
        progressValueChanged(row);
    }
    qDebug() << "Indexed areas = " << _areasCount;

    _model.setIndexedAreasImage(image);
    _model.setIndexedAreas(indexImage);
}

void AreaIndexingTask::doCancel()
{

}

bool AreaIndexingTask::fillScanline(ColorImage &image, IndexImage &indexImage, int row, int col,
                                    QRgb oldColor, QRgb newColor)
{
    if (oldColor == newColor) {
        return false;
    }
    int width = image.width();
    int height = image.height();

    if ((0 <= row) && (row < height) && (0 <= col) && (col < width)) {
        QRgb pixel = image.pixel(col, row);        
        if (pixel == oldColor) {
            // draw scanline from start position to the right
            int x = col;
            while ((x < width) && (image.pixel(x, row) == oldColor)) {                
                image.setPixel(x, row, newColor);
                indexImage.setIndex(x, row, _areasCount + 1);
                x++;
            }                        
            x = col - 1;
            // draw scanline from start position to the left
            while ((x >= 0) && (image.pixel(x, row) == oldColor)) {
                image.setPixel(x, row, newColor);
                indexImage.setIndex(x, row, _areasCount + 1);
                x--;
            }
            // test for new scanlines to the up
            x = col;
            while ((x < width) && (image.pixel(x, row) == newColor)) {                
                fillScanline(image, indexImage, row + 1, x, oldColor, newColor);
                x++;
            }
            x = col - 1;
            while ((x >= 0) && (image.pixel(x, row) == newColor)) {
                fillScanline(image, indexImage, row + 1, x, oldColor, newColor);
                x--;
            }
            // test for new scanlines to the down
            x = col;
            while ((x < width) && (image.pixel(x, row) == newColor)) {
                fillScanline(image, indexImage, row - 1, x, oldColor, newColor);
                x++;
            }
            x = col - 1;
            while ((x >= 0) && (image.pixel(x, row) == newColor)) {
                fillScanline(image, indexImage, row - 1, x, oldColor, newColor);
                x--;
            }
            return true;
        }
    }
    return false;
}

AreaIndexingModel::AreaIndexingModel(QObject *parent) :
    ImageModel(parent)
{

}

AreaIndexingTask* AreaIndexingModel::indexAreas()
{
    return new AreaIndexingTask(*this);
}

void AreaIndexingModel::setDetectedAreasImage(const BinaryImage& image)
{
    setFeature(EDetectedAreasImage, 0, qVariantFromValue(image));
    setFeature(EIndexedAreas, 0, qVariantFromValue(ColorImage()));
    setFeature(EIndexedAreasImage, 0, qVariantFromValue(ColorImage()));
}

BinaryImage AreaIndexingModel::detectedAreasImage()
{
    return qVariantValue<BinaryImage>(feature(EDetectedAreasImage, 0));
}

void AreaIndexingModel::setIndexedAreasImage(const ColorImage &image)
{
    setFeature(EIndexedAreasImage, 0, qVariantFromValue(image));    
    emit areasImageIndexed(image);
}

ColorImage AreaIndexingModel::indexedAreasImage()
{
    return qVariantValue<ColorImage>(feature(EIndexedAreasImage, 0));
}

void AreaIndexingModel::setIndexedAreas(const IndexImage &image)
{
    setFeature(EIndexedAreas, 0, qVariantFromValue(image));    
    emit areasIndexed(image);
}

IndexImage AreaIndexingModel::indexedAreas()
{
    return qVariantValue<IndexImage>(feature(EIndexedAreas, 0));
}
